(function ($) {
  function createSortableTable(tableGroup) {

    var table = tableGroup.querySelector('table');
    var headerGroup = table.querySelector('thead');
    var headerRow = headerGroup.querySelector('tr');
    var headers = headerRow.querySelectorAll('th');
    var rowGroup = table.querySelector('tbody');
    var rows = rowGroup.querySelectorAll('tr');
    var captionElement = table.querySelector('caption');
    var caption = captionElement.innerText;

    var liveRegion = tableGroup.querySelector('#liveRegion');
    var readCaptions = liveRegion.getAttribute('readCaptions');
    if (readCaptions === null) {
      readCaptions = false;
    }
    liveRegion.classList.add('deque-visuallyhidden');
    liveRegion.notify = function (text) {
      liveRegion.innerHTML = text;
    };

    var sortOrder = null;
    var sortDirection = -1;

    function getSortHeader() {
      if (sortOrder === null) {
        return null;
      }
      return headerRow.children[sortOrder];
    }

    function getSortLabel() {
      var header = getSortHeader();
      if (!header) {
        return null;
      }
      return header.innerText;
    }

    function getSortDirection() {
      return sortDirection > 0 ? 'ascending' : 'descending';
    }

    function getSortInfo() {
      if (sortOrder === null) {
        return 'unsorted';
      }

      return 'sorted by ' + getSortLabel() + ', ' + getSortDirection();
    }

    function renderSorting() {
      updateCaption();
      updateAriaSort();
      updateLiveRegion();
    }

    function updateAriaSort() {
      for (var i = 0; i < headerRow.children.length; i++) {
        var child = headerRow.children[i];

        if (sortOrder !== null && i === Math.abs(sortOrder)) {
          var direction = getSortDirection();
          child.setAttribute('aria-sort', direction);
        } else {
          child.removeAttribute('aria-sort');
        }
      }
    }

    function updateCaption() {
      var captionText = caption + ', ' + getSortInfo();
      captionElement.innerText = captionText;
    }

    function updateLiveRegion() {
      if (readCaptions) {
        var captionText = 'Table ' + caption + ' is now ' + getSortInfo();
        liveRegion.notify(captionText);
      }
    }
    rows = Array.prototype.slice.call(rows);
    var isValid = rows.every(function (row) {
      return row.children.length === headers.length;
    });

    if (!isValid) {
      throw new Error('Each row must be the same length as the headers row.');
    }

    headers = Array.prototype.slice.call(headers);
    headers.forEach(function (header, i) {
      createHeaderCell(header, function (e) {
        e.preventDefault();
        rows = sortByIndex(rows, i);
        table.renderData(rows);
      });
    });

    table.renderData = function (rows) {
      rowGroup.innerHTML = toHTML(rows);
      renderSorting();
    };

    table.renderData(rows);

    function sortByIndex(rows, index) {
      if (sortOrder === index) {
        sortDirection = -sortDirection;
        return rows.reverse();
      } else {
        sortOrder = index;
        return rows.sort(function (a, b) {
          a = Array.prototype.slice.call(a.children);
          b = Array.prototype.slice.call(b.children);
          var aVal = a[index].innerText;
          var bVal = b[index].innerText;

          if (!isNaN(parseInt(aVal)) && !isNaN(parseInt(bVal))) {
            if (parseInt(aVal) < parseInt(bVal)) {
              return -1;
            }
            if (parseInt(aVal) > parseInt(bVal)) {
              return 1;
            }
            return 0;
          } else {
            if (aVal < bVal) {
              return -1;
            }
            if (aVal > bVal) {
              return 1;
            }
            return 0;
          }
        });
      }
    }

    var firstOne = table.querySelector('.sortableColumnLabel');
    if (firstOne) {
      firstOne.click();
    } // give the table a default sort...
  }

  function createHeaderCell(header, handler) {
    var button = header.querySelector('button');
    button.setAttribute('tabindex', '0');

    button.addEventListener('click', handler);
  }

  function toHTML(rows) {
    return rows.map(function (row) {
      row = Array.prototype.slice.call(row.children);
      return '<tr role="row">\n    ' + row.map(function (item, index) {
        if (index === 0) {
          return '<th scope="row" role="rowheader">' + item.innerText + '</th>';
        }
        return '<td role="gridcell">' + item.innerText + '</td>';
      }).join('') + '</tr>';
    }).join('');
  }

  function activateAllSortableTables() {
    var sortableTables = document.querySelectorAll('.deque-table-sortable-group');
    for (var i = 0; i < sortableTables.length; i++) {
      createSortableTable(sortableTables[i]);
    }
  }
  activateAllSortableTables();
})(jQuery);